from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render

from meidou_mall.apps.goods.models import SKU
from meidou_mall.apps.orders.models import OrderInfo, OrderGoods
from meidou_mall.apps.users.models import Address
from meidou_mall.utils.my_loginview import LoginRequiredView


from django_redis import get_redis_connection
from decimal import Decimal
import json
from django import http
from django.utils import timezone
import random
from decimal import Decimal

from meidou_mall.utils.response_code import RET
from django.db import transaction


# Create your views here.
#1,获取订单结算页
class OrderSettlement(LoginRequiredView):
    def get(self,request):

        #1, 获取用户收货地址
        addresses = Address.objects.filter(user_id=request.user.id,is_deleted=False).all()

        #2, 获取用户选中购物车的数据
        redis_conn = get_redis_connection("carts")
        cart_dict = redis_conn.hgetall("carts_%s" % request.user.id)
        sku_ids = redis_conn.smembers("selected_%s"%request.user.id)
        sku_list = []

        total_count = 0 #总数量
        total_amount = Decimal(0.0)#总金额
        for sku_id in sku_ids:
            sku = SKU.objects.get(id=sku_id)
            sku_dict = {
                "id":sku.id,
                "default_image_url":sku.default_image_url.url,
                "name":sku.name,
                "price":str(sku.price),
                "count":int(cart_dict[sku_id]),
                "amount":str(int(cart_dict[sku_id]) * sku.price)
            }
            sku_list.append(sku_dict)

            #累加
            total_count += int(cart_dict[sku_id])
            total_amount += (int(cart_dict[sku_id]) * sku.price)

        #运费和实付款
        freight = Decimal(10)
        payment_amount = total_amount + freight


        #携带数据,渲染页面
        context = {
            "addresses":addresses,
            "sku_list":sku_list,
            "total_count":total_count,
            "total_amount":total_amount,
            "freight":freight,
            "payment_amount":payment_amount
        }
        return render(request,'place_order.html',context=context)

#2,订单提交
class OrderCommitView(LoginRequiredView):
    @transaction.atomic
    def post(self,request):
        #1,获取参数
        data_dict = json.loads(request.body.decode())
        address_id = data_dict.get("address_id")
        pay_method = data_dict.get("pay_method")

        #2,校验参数
        #2,1 为空校验
        if not all([address_id,pay_method]):
            return http.JsonResponse({"code":RET.PARAMERR,"errmsg":"参数有误"})

        #2,2 判断地址是否存在
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({"code": RET.DBERR, "errmsg": "地址不存在"})

        #2,3 判断是否方式是否合法
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM["CASH"],OrderInfo.PAY_METHODS_ENUM["ALIPAY"]]:
            return http.JsonResponse({"code": RET.DATAERR, "errmsg": "支付方式有误"})

        #3,订单信息表入库
        #3,1 生成订单编号(原则:尽量保证order_id的唯一性#)
        order_id = timezone.now().strftime("%Y%m%d%H%M%S") + "%09d%d"%(random.randint(0,999999999),request.user.id) #时间戳 + 随机字符串9 + 用户id

        #3,2 判断订单状态
        if pay_method == OrderInfo.PAY_METHODS_ENUM["CASH"]:
            status = OrderInfo.ORDER_STATUS_ENUM["UNPAID"]
        else:
            status = OrderInfo.ORDER_STATUS_ENUM["UNSEND"]

        #TODO 设置保存点
        sid = transaction.savepoint()

        order_info = OrderInfo.objects.create(
            order_id=order_id,
            user=request.user,
            address=address,
            total_count=0,
            total_amount=Decimal(0.0),
            freight=Decimal(10),
            pay_method=pay_method,
            status=status
        )

        #4,订单商品入库
        redis_conn = get_redis_connection("carts")
        cart_dict = redis_conn.hgetall("carts_%s"%request.user.id)
        sku_ids = redis_conn.smembers("selected_%s"%request.user.id)

        for sku_id in sku_ids:
            while True:
                #4,1 获取sku,count
                sku = SKU.objects.get(id=sku_id)
                count = int(cart_dict[sku_id])

                #4,2 库存判断
                if count > sku.stock:
                    #TODO 回滚
                    transaction.savepoint_rollback(sid)
                    return http.JsonResponse({"code":RET.DATAERR,"errmsg":"库存不足"})

                #TODO 模拟并发下单
                # import time
                # time.sleep(5)

                #TODO 解决并发下单
                old_stock = sku.stock
                old_sales = sku.sales
                new_stock = old_stock - count
                new_sales = old_sales + count

                #调用update返回的结果是整数,表示影响的行数
                ret = SKU.objects.filter(id=sku_id,stock=old_stock).update(stock=new_stock,sales=new_sales)

                if ret == 0:
                    # transaction.savepoint_rollback(sid)
                    # return http.JsonResponse({"code": RET.DBERR, "errmsg": "库存修改失败"})
                    continue

                #4,3 库存减少,销量增加
                # sku.stock -= count
                # sku.sales += count
                # sku.save()

                #4,4 创建订单商品对象
                OrderGoods.objects.create(
                    order=order_info,
                    sku=sku,
                    count=count,
                    price=sku.price,
                )

                #4,4 累加订单信息表
                order_info.total_count += count
                order_info.total_amount += (count * sku.price)

                #跳出
                break

        #5,保存订单信息表
        order_info.save()
        transaction.savepoint_commit(sid) #TODO 提交保存点(事务)

        #6,清除购物车中已经付过款的数据
        redis_conn.hdel("carts_%s"%request.user.id,*sku_ids)
        redis_conn.srem("selected_%s"%request.user.id,*sku_ids)

        #7,返回响应
        return http.JsonResponse({"code":RET.OK,"order_id":order_id})

#3,订单成功
class OrderSuccessView(LoginRequiredView):
    def get(self,request):
        #1,获取参数
        order_id = request.GET.get("order_id")
        payment_amount = request.GET.get("payment_amount")
        pay_method = request.GET.get("pay_method")

        #2,校验参数
        #2,1 为空校验
        if not all([order_id,payment_amount,pay_method]):
            return http.HttpResponseForbidden("参数不全")

        #2,2 订单是否存在
        try:
            order = OrderInfo.objects.get(order_id=order_id)
        except Exception as e:
            return http.HttpResponseForbidden('订单不存在')

        #2,3 支付方式是否正确
        if pay_method not in ["1","2"]:
            return http.HttpResponseForbidden("支付方式有误")

        #3,渲染页面
        context = {
            "order_id":order_id,
            "payment_amount":payment_amount,
            "pay_method":pay_method
        }
        return render(request,'order_success.html',context=context)
